#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         MultipleChoiceEditlet.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Brian Oliver
#
# Description:  This file defines the MultipleChoiceEditlet class, that is
#               used to generate the Multiple Choice
#               'Answers' property editor.
#
# Note:         Only one of these Editlets should ever be generated
#               per propertyeditor page
#
# See Also:     PropertyEditlet, PropertyRefleciton, 
#               PropertyDefinition, PropertyAccess 
#####################################################################

#####################################################################
## KnowledgeEngine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Editlet import Editlet
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *
from Products.KnowledgeEngine.Editlets.HTML.HTMLEditlet import *
from Products.KnowledgeEngine.Components.MultipleChoice.MultipleChoice import Answer

#####################################################################
## Zope Library Imports
# (none)
 
#####################################################################
## Python Library Imports
import string


def loadTemplate():    
    """ Reloads the HTML Template from the filesystem """
    
    # Open the file
    filename = os.path.dirname(__file__) + '/MultipleChoiceEditlet.html'
    file = open(filename)
    
    # Read the contents and return
    return "\n".join(file.xreadlines())
        
    


#####################################################################
## MultipleChoiceEditlet Class Definition
class MultipleChoiceEditlet(HTMLEditlet):
    """
        An editlet for editing Numeric properties  
    """
    
    #---------------------------------------------------------------#
    
    def isEditable(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns if the specified propertyDefinition can be
            edited by this editlet
        """

        return propertyDefinition.getType() == "ANSWER_LIST"
        
    #---------------------------------------------------------------#

    def generateEditorFor(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns a HTML editlet for the specified property.
        """
                        
        #ensure that we use a writeable editlet (if possible) if we are dealing with a mandatory property and we don't yet have a value
        if propertyDefinition.isMandatory() and propertyAccess is not None and (not hasattr(propertyAccess, propertyDefinition.getIdentity()) or getattr(propertyAccess, propertyDefinition.getIdentity()) is None):
            
            #we want an editletEVAP with the most permissions (which may not include write access)
            editletEVAP = propertyDefinition.getConstructorEVAP() | propertyDefinition.getPropertyEditorEVAP()
        
        else:
            #determine the type of editlet we need to produce based on editlet value access permission (EVAM)
            editletEVAP = iif(isForConstructor, propertyDefinition.getConstructorEVAP(), propertyDefinition.getPropertyEditorEVAP())
                
        #-----------------
        #no property editor is required
        if editletEVAP == evap_NONE:
            result = ""

        #-----------------
        #a read-only property editor is required
        elif editletEVAP == evap_READONLY:

            #get the value for the property
            if isForConstructor or propertyAccess is None:
                value = propertyDefinition.getDefaultValue()
            else:
                value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())
            
            #TODO: create the editor
            result = "*insert read-only value here*" % (value,)
        
        #-----------------
        #a writeable property editor is required
        else: 
       
            #get the value for the property (if possible)
            if editletEVAP == evap_WRITEONLY:
                value = ""
            else:
                if isForConstructor or propertyAccess is None:
                    value = propertyDefinition.getDefaultValue()
                else:
                    #get the value for the property
                    value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())

            #generate the appropriate epoz editor link
            if context != None and self.isEpozAvailable(context):
                #generate an enabled epoz link
                epozLink = """<a href="javascript:void(0)" onClick="javascript:window.open('%s/epozEditor?propertyIdentity=' + this.previousSibling.id,'epozEditor','width=760,height=580,top=20,left=20,menubar=no,toolbar=no,scrollbars=yes,resizable=yes,status==yes').focus();"><img src="/misc_/kupu/kupu_icon.gif" border="0" align="top"></a>""" % (context.getAbsolutePath(),)

            else:
                #generate an disabled epoz icon
                # epozLink = """<img src="/misc_/kupu/kupu_icon.gif" border="0" align="top">"""           
                
                # 20070309 johnm    Probably best to *not* show a link to the
                #                   kupu/epoz editor if it's not available
                epozLink = ''
                
            # If we're running in debug more, reload the template
            if os.environ.get('Z_DEBUG_MODE',0):
                self.editletHTMLTemplate = loadTemplate()                
                
            #create the editor
            result = string.replace(self.editletHTMLTemplate, "EPOZ", epozLink)       
                        
        return result
        
    #---------------------------------------------------------------#

    def generateEditorJSInitialisation(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns Javascript to initialise the current page for this editlet
        """
        
        #the resulting javascript
        javascript = ""
        
        #TODO: modify the following to support read only and write only properties
        
        #we use the default answers for a constructor
        if isForConstructor:
            answerList = propertyDefinition.getDefaultValue()
        else:
            answerList = propertyAccess.getAnswerList()
        
        #add each of the answers to the javascript model        
        for answer in answerList:
            if answer.isCorrect():
                isCorrect = "true"
            else:
                isCorrect = "false"
        
            javascript += 'addAnswer("%s", "%s", "%s", "%s", %s, %s);' % (asJavaScript(answer.getAnswerID()), asJavaScript(answer.getContent()), asJavaScript(answer.getAssessmentContent()), asJavaScript(answer.getReportContent()), answer.getScore(), isCorrect)                     
        
        #add the instruction to render the answers
        javascript += "renderAnswers();"
        return javascript
        
    #---------------------------------------------------------------#

    def containsPropertyValue(self, propertyDefinition, REQUEST):
        """
            Determines if the provided request contains
            a value for the specified propertyDefinition.
            
            This method is used (and is useful for) determining and
            updating the values of properties from property editors.
            
            All editlet implementations must override this method.            
        """
        
        return REQUEST.has_key("keAnswerCount")
        
    #---------------------------------------------------------------#

    def updatePropertyWith(self, propertyDefinition, propertyAccess, REQUEST=None):
        """
            Attempts to update the specified property on the
            object implementing the PropertyAccess interface with the
            specified HTTP REQUEST.
        """

        #we're going to build a new answerlist
        answerList = []

        #get the number of answers from the request
        nrAnswers = int(REQUEST["keAnswerCount"])

        #create Answer instances for each of the answers
        for idx in range(0,nrAnswers):

            #get the values for the answer
            answerID = REQUEST["keAnswerID%s" % idx]
            answerContent = REQUEST["keAnswerContent%s" % idx]
            answerAssessmentContent = REQUEST["keAnswerAssessmentContent%s" % idx]
            answerReportContent = REQUEST["keAnswerReportContent%s" % idx]
            answerScore = float(REQUEST["keAnswerScore%s" % idx])            

            #this is to work-around the problem where some browsers don't send back the state of unchanged dynamically created radio buttons
            if REQUEST.has_key("radioIsCorrect"):                       
                isCorrect = int(REQUEST["radioIsCorrect"]) == idx
            else:
                isCorrect = false
            option = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[idx]

            #create the next answer
            answer = Answer(answerID, answerContent, answerAssessmentContent, answerReportContent, answerScore, isCorrect, option)

            #add the answer to the list
            answerList.append(answer)

        #ensure one of the answers is correct!
        if len([answer for answer in answerList if answer.isCorrect()]) == 0:
            #attempt to use the previous correct answer (if there is one)
            originalAnswerList = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())
            originalCorrectAnswer = [answer for answer in originalAnswerList if answer.isCorrect()]
            if len(originalCorrectAnswer) == 0:
                originalCorrectAnswer = None
                answerList[0].setIsCorrect(true)
            else:
                #get the desired correct answer    
                originalCorrectAnswer = originalCorrectAnswer[0]

                #search the new answers for the original correct answer and set it when found
                isFound = false
                for answer in answerList:
                    if not isFound and answer.getAnswerID() == originalCorrectAnswer.getAnswerID():
                        answer.setIsCorrect(true)
                        isFound = true

                #not found?  so set the first answer as the correct one
                if not isFound:
                    answerList[0].setIsCorrect(true)


        # Check we have a value if it isMandatory
        propertyDefinition.verifyMandatoryValue(answerList)


        #set the value for the property from the REQUEST
        propertyAccess.setPropertyValue(propertyDefinition.getIdentity(), answerList)
                    
    #---------------------------------------------------------------#

    editletHTMLTemplate = loadTemplate()
        
    #---------------------------------------------------------------#

#####################################################################
## Class Initialisation

# Register Editlet Information with the Knowledge Engine
registerEditlet("MultipleChoiceEditlet", MultipleChoiceEditlet())

#####################################################################
